SPI转can芯片CSM300详解、Linux驱动移植调试笔记
一口君最近移植了一款SPI转CAN的芯片CSM300A,在这里和大家做个分享。
一、CSM300概述
CSM300(A)系列是一款可以支持 SPI / UART 接口的CAN模块。
1. 简介
CSM300(A)系列隔离 SPI / UART 转 CAN 模块是集成微处理器、 CAN 收发器、 DC-DC 隔离电源、 信号隔离于一体的通信模块, 该芯片可以很方便地嵌入到具有 SPI 或 UART 接口的设备中, 在不需改变原有硬件结构的前提下使设备获得 CAN 通讯接口, 实现 SPI 设备或 UART 设备和 CAN 总线网络之间的数据通讯。
外观
2. 参数
实现 SPI 或 UART 与 CAN 接口的双向数据通信; CAN 总线符合“ISO 11898-2”标准; 集成 1 路 SPI 接口, 支持用户自定义的速率, 最高可达 1.5Mbit/s(非自定义协议转换) ,或 1Mbit/s(自定义协议转换) ; 集成 1 路 UART 接口, 支持多种速率, 最高可达 921600bps; 集成 1 路 CAN 通讯接口, 支持多种波特率, 最高可达 1Mbps; 隔离耐压 2500VDC; 工作温度:-40℃~+85℃; 电磁辐射 EME 较低; 电磁抗干扰 EMS 较高;
如上图所示 CSM300是5V工作电压,CSM300A是3.3V工作电压。
如果MCU、MPU侧工作电压不是1.8V那么就需要增加一个level shift来进行电压转换。
此次调试的板子使用的是CSM300A,只使用其中的SPI接口。
3. 引脚定义及参考电路
使用SPI转CAN功能时, 需要将MODE引脚接至高电平。MCU的SPI接口与CSM300(A)的 SPI 接口连接,同时 MCU 需要提供 GPIO 与 RST、 INT、 CTL0、 CTL1 引脚连接,实现对 CSM300(A)的有效监测与控制。若需要通过 MCU 对CSM300(A)进行配置,则需要额外的 GPIO 与 CFG 引脚连接。
引脚说明:
引脚功能说明如下:
MODE脚直接接高电压(高电平对应SPI模式,低电平对应UART模式); 10、11、12外接CAN总线,主要用于CAN通信; 3、6、7、24、19引脚接MCU/MPU,配置CSM300A的模式和读写操作都要依靠这几个引脚; 18、21、22、23这4个引脚需要接到MCU/MPU的SPI控制器引脚,主要是CPU侧发送配置信息和读写数据的SPI通路; 20 是INT引脚,CSM300A收到数据后,满足一定条件就会下拉该引脚,产生中断信号,通知CPU读取数据。
二、工作模式
1. 工作模式分类
CSM300(A)上电后, MODE、 CFG 引脚电平会决定产品处于 4 种不同的工作模式的其中一种:SPI 转 CAN 模式、 UART 转 CAN 模式、 SPI 配置模式、 UART 配置模式。
如上表所示:
如果我们要配置CSM300A,就是要设置CSM300A模式为SPI配置模式,那么就需要将MODE引脚置为1,CFG置为0,RST置为1; 如果我们要通过CSM300A读写数据,就是要设置CSM300A模式为SPI转CAN模式,那么就需要将MODE引脚置为1,CFG置为1,RST置为1; 读写数据的操作,都属于SPI转CAN模式,不需要切换模式。 若需要切换产品的工作模式,更改引脚电平后,必须对产品进行复位,才能使其进入设 定的工作模式。需要注意的是,为保证成功复位, 复位保持时间最少为 100us,复位后, 产品初始化等待时间最少 3ms,待产品初始化完成后,才能进行正常操作。
下图是不同模式切换的时序图。
2. SPI 转 CAN 模式(数据读写)
在此工作模式下, CSM300(A)始终作为 SPI 从机, SPI 限定工作在模式 3(CPOL、 CPHA 均为 1),数据长度限定为 8 位, MSB 高位先传输。透明转换、透明带标识转换下最高通信 速率为 1.5Mbps,自定义协议转换最高通信速率为 1Mbps。
SPI 主机可以发送数据至 CAN 总线端, 且可接收 CAN 总线端收到的数据。此时 UART 接口无效,不会处理任何出现在 UART 接口的数据,也不会返回 CAN 总线端接收到的数据 至 UART。
SPI 帧 SPI 一次片选有效至片选无效之间的数据定义为一帧数据。帧与帧之间读写缓冲区数据应有 40us 的时间间隔。
3. SPI 配置模式
在此模式下, CSM300(A)处于等待配置状态, 无法向 CAN 端发送或接收数据。此模式下仅能通过 SPI 接口进行配置。
三、主机控制
CSM300(A)有两个 SPI 主机控制引脚 CTL0, CTL1, 受主机端控制。主机通过控制 CTL0, CTL1 引脚, 使 CSM300(A)进入不同的功能状态,实现对 CSM300(A)不同操作目的。主机端控制引脚电平不同对应功能如下表所示:
主机可以通过读从机当前状态来获取产品当前可以读取的字节数以及可以写入的字节 数。主机将功能选择为主机读状态,然后通过 SPI 读出 4 个字节,即为状态码。状态码由 32 个位构成,具体定义如下表所示。
若定义 status[]数组为 8 位整型, 通过 SPI 读状态依次读出的数据为 status[0]、 status[1]、 status[2]、 status[3],则其数据结构如下图:
四、反馈机制(中断)
CSM300(A)只能作为 SPI 从机,不能主动地控制其他 SPI 总线设备,所以如果接收CAN数据帧之后,必须主动返回给CPU侧。
CSM300(A)硬件上的 INT 反馈引脚, 此引脚与主机连接,出现以下两种情况时, INT 引脚会由高电平变成低电平,通知主机进行读数据操作(为避免数据丢失,建议主机使用低 电平触发方式检测):
CAN 缓冲区 CAN 帧数达到设置的触发点时 当产品 CAN 总线端接收缓冲区接收到的 CAN 帧数达到触发点时, INT 引脚电平置低, 直到缓冲区清空, INT 引脚才会恢复高电平。用户可以在获得 INT 信号之后查询 CSM300(A) 的状态,获取可读字节数,然后读取缓冲区 CAN 数据。
CAN 缓冲区数据少于触发帧数,且在设定时间内主机未读取时 CAN 缓冲区有数据但少于触发帧数时,若总线长时间未有新增数据,且主机未进行读 取操作时, CAN 接收缓冲区的数据将有可能长期得不到处理, 这就导致数据的实时性不高。为了解决少量数据的实时性问题, CSM300(A)内部设置了一个计时器,若 CAN 缓冲区的数 据在一定时间内未被读取, 将触发 INT 引脚置低,通知主机读取数据。CSM300(A)在接收 到最后一帧数据时, 计时器启动,主机进行读取操作时复位计时器。
五、组网方式
CAN 总线一般使用直线型布线方式,总线节点数可达 110 个。布线推荐使用屏蔽双绞线, CANH、 CANL 与双绞线线芯连接, CGND 与屏蔽层连接,最后屏蔽层单点接地。
得益于 CSM300(A)的最低波特率 5kbps,总线的最长通信距离可达 10km。
六、移植
1. 硬件连接图
如上图所示:
SOC上已经集成了SPI控制器,厂家的sdk已经包含了spi控制器的设备树和驱动信息; SOC的SPI控制器引脚需要先连接level shift进行升压,板子电压是1.8V,而CSM300要求电压是3.3V; SOC的GPIO 76/107/113/114通过level shift分别连接CSM300A的RST/CFG/CTL1/CTL0; 在PC上运行CAN-Test软件,可以通过USB转CAN设备从CAN总线上读取和发送数据。
【注】USB转CAN设备,可以自行搜索,杜绝广告。
2. 设备树
以下是官方提供的设备树:
csm300@0 {
pinctrl-names = "default";
pinctrl-0 =<&pinctrl_csm300>;
gpios=<&gpio3 21 0 /*ctl0*/
&gpio3 22 0 /*ctl1*/
&gpio3 30 0 /*rst*/
&gpio3 31 0 /*cfg*/
>;
interrupt-parent = <&gpio3>;
interrupts = <26 IRQ_LEVEL_LOW>;
compatible = "zhiyuan,csm300";
spi-max-frequency = <500000>;
reg = <1>;
status = "okay";
};
以下是根据自己的平台修改的结果,读者移植的时候需要根据自己的平台来移植,不可教条。
csm300@0 {
pinctrl-names = "default";
gpios=<&gpio 114 0 /*ctl0*/
&gpio 113 0 /*ctl1*/
&gpio 76 0 /*rst*/
&gpio 107 0 /*cfg*/
>;
interrupt-parent = <&gpio>;
interrupts = <196 IRQ_LEVEL_LOW>;
compatible = "zhiyuan,csm300";
spi-max-frequency = <500000>;
reg = <0>;
status = "okay";
};
3. 驱动
官方会提供驱动程序csm300.c,具体实际原理,本篇暂不讨论。
拷贝到以下目录:
drivers/net/can/spi
修改本级目录下的Makefile
obj-$(CONFIG_CAN_CSM300) += csm300.o
修改本级目录下的Kconfig
config CAN_CSM300
tristate "Microchip CSM300 driver"
depends on SPI
---help---
Driver for the Microchip CSM300 .
执行make menuconfig
驱动位置如下:
选中该驱动:
重新编译内核即可。
注意:该驱动还需要依赖CAN和SPI,一定要选上 。
4. 增加调试接口
在调试过程中,会有各种原因导致csm300驱动无法注册成功,那如何判定是spi控制器驱动有问题,还是csm300驱动有问题呢?
为了方便通过spi控制器发送出波形,我们增加以下代码,用于在板子目录/sys/bus/spi/drivers/csm300中创建state文件节点,通过写入不同的值来产生spi数据,或者控制RST、 CFG、 CTL0、 CTL1这4个引脚。
增加函数csm300_spi_store()
重点说明一下函数**check_csm300()**是驱动自带的用于测试CSM300的SPI通信功能的函数。
该函数会先将CSM300A设置为SPI配置模式,然后写入9个数据,然后再读取出数据,进行校验数据是否正确。
修改probe函数
struct net_device *global_net = NULL ;
csm_probe()
{
……
global_net = net;
ret = check_csm300(net);
……
ret = driver_create_file(&(csm300_can_driver.driver),&driver_attr_state);
if(ret < 0){
ret = -ENOENT;
goto out_free;
}
……
}
测试命令 进入csm300模块目录
cd /sys/bus/spi/drivers/csm300
产生spi数据
echo 3 > state
拉高RST、 CFG、 CTL0、 CTL1
echo 1 > state
拉低RST、 CFG、 CTL0、 CTL1
echo 0 > state
5. 正确的开机log与波形
开机后驱动会调用check_csm300()来测试spi通道,发送的数据为F7:F8:02……
以下为SPI接口的CLK和MOSI引脚的波形:
可以看到数据与我们发送的是一致的。
6. 接收数据波形图
接收数据步骤如下:
运行于PC上的CAN Test 软件发送数据 00 01 02 03 04 05 06 07, 经过USB转CAN设备后,转换成了差分信号, 到达CSM300A之后,信号被调制成矩形方波, CSM300A通过拉低引脚INT向cpu发送中断信号,调用CSM300A注册的中断函数, 运行于CPU上的CSM300A中断程序通过SPI接口读走CSM300A上的数据, CSM300A缓冲区数据被读走后,拉高INT, 驱动程序将接收到的数据上传给应用层,于是candump命令得到了CAN帧的数据。
数据发送过程和上述过程类似。
7. CAN命令
如果文件系统中没有can命令,需要自行移植。
1) 设置波特率并开启can0口
ip link set can0 up type can bitrate 800000
2) 发送数据
cansend can0 1F334455#1122334455667788
3) 查看接收的数据
candump can0
七、出错记录
调试过程中遇到了很多的错误,CSM300A定位问题步骤:
首先用示波器测试CSM300的MOSI引脚的波形,是不是和第七章第5节的波形一致,如果不一致,说明SPI控制器驱动加载不正确; 要通过SPI控制器产生数据,使用命令echo 3 > state; 如果波形一致,就测量RST、 CFG、 CTL0、 CTL1这四个引脚,查看电平是否正确; RST、 CFG、 CTL0、 CTL1控制是否正确,可以用echo 0 > state、echo 1 > state分别拉低拉高,查看对这几个引脚的控制是否正常。
基本上照着这个思路去调试很快就能定位到问题。
以下是驱动加载出错的log,出错的原因主要是调用check_csm300()函数向CSM300A写入数据再读取出来后数据不匹配,从而判定加载出错。
1. CFG引脚拉低异常
现象:check_csm300()函数始终报错。
分析:check不成功,基本上原因是SPI控制器与CSM300通信出了问题。首先用示波器,查看SPI发送的数据是否正常到达CSM300(用示波器抓取SSEL、CLK、MOSI),结果是正常的。
于是检测检测 RST、 CFG、 CTL0、 CTL1四个引脚。如下图所示,使用echo 0 > state 拉低CFG引脚,发现没有拉到0V。
解决方案:
交给硬件工程师去改。这兄弟给CFG加了一个反向电阻,驱动部分需要将所有设置CFG的代码,全部反置。
gpio_set_value(priv->CFG,0);
修改成
gpio_set_value(priv->RST,1);
gpio_set_value(priv->CFG,1);
修改成
gpio_set_value(priv->RST,0);
2. RST 延时不够
现象:echo 0 > state 可以拉低,测量也是正确的,但是CSM300始终无法接收到数据帧。
分析:一般数据接收不到,有两种可能:就是CSM300给出的中断信号CPU没有截取到,CSM300没有处于SPI转CAN模式。
先用示波器确定了,USB转CAN的数据已经成功到达CSM300,于是检测对应的引脚电平 RST、 CFG、 CTL0、 CTL1,发现也是对的。
检查中断计数,用cat /proc/interrupts查看CSM300是否有中断计数,结果发现数据为0。
怀疑CSM300没有rst成功,于是执行echo 3 > state,查看rst是否正确设置,结果发现以下波形,确定了该引脚拉高比较缓慢,所以CSM300采样不到这个电平。
修改方法:驱动中每次rst操作,都要增加延迟时间:
gpio_set_value(priv->RST,0);
usleep_range(2000,2300);
gpio_set_value(priv->RST,1);
修改后,执行echo 3 > state,RST波形如下所示。
官方资料下载
https://www.zlg.cn/index.php/power/power/product/id/218.html
-THE END-
推荐阅读
【1】100ASK_IMX6ULL arm板子如何显示图片、汉字、划线、背景色
【2】到底什么是Cortex、ARMv8、arm架构、ARM指令集、soc?一文帮你梳理基础概念【科普】 必读
【3】搞懂进程组、会话、控制终端关系,才能明白守护进程干嘛的?
【4】一个多线程的简单例子让你看清线程调度的随机性
【5】在100ASK_IMX6ULL arm板子上移植个刷卡器【6】Linux库概念,动态库和静态库的制作,如何移植第三方库
本公众号全部原创干货已整理成一个目录,点击「干货」即可获得。
后台回复「进群」,即可加入技术交流群,进群福利:免费赠送Linux学习资料。